package pro.reznick.geoalarm;

import android.app.AlarmManager;
import android.app.Service;
import android.content.Context;
import android.content.Intent;

import java.util.ArrayList;
import java.util.List;


import android.os.Binder;
import android.os.IBinder;
import pro.reznick.geoalarm.exceptions.GeoAlarmValidationException;

public class GeoAlarmController extends Service
{
    Context context;
    private AlarmDao alarmDao;
    private ControllerBinder binder;

    private List<ControllerEventHandler> eventHandlers = new ArrayList<ControllerEventHandler>();


    @Override
    public void onCreate()
    {
        super.onCreate();
        this.context = getApplicationContext();
        Intent intent = new Intent(context, GeoAlarmService.class);
        context.startService(intent);

        alarmDao = new AlarmDao(context);
        binder = new ControllerBinder();
    }

    public void exitApp()
    {
        Intent intent = new Intent(context, GeoAlarmService.class);
        context.stopService(intent);
        alarmDao.close();
    }

    public void createNewAlarm(String latitude, String longitude,
                               String distanceInMeters, String name, String message) throws GeoAlarmValidationException
    {

        double lng = toDouble(longitude, "Longitude");
        double lat = toDouble(latitude, "Latitude");
        int dst = toInt(distanceInMeters, "Distance");

        AlarmData alarm = new AlarmData(lng, lat, dst, name, message, true);
        alarmDao.newAlarm(alarm);

        for (ControllerEventHandler eh : eventHandlers)
        {
            eh.onAlarmAdded(alarm);
        }
    }

    public void updateAlarm(int alarmId, String latitude, String longitude,
                            String distanceInMeters, String name, String message) throws GeoAlarmValidationException
    {

        double lng = toDouble(longitude, "Longitude");
        double lat = toDouble(latitude, "Latitude");
        int dst = toInt(distanceInMeters, "Distance");

        AlarmData alarm = new AlarmData(lng, lat, dst, name, message, true);
        alarm.setId(alarmId);
        alarmDao.updateAlarm(alarm);

        for (ControllerEventHandler eh : eventHandlers)
        {
            eh.onAlarmUpdated(alarm);
        }
    }


    public void deleteAlarm(AlarmData alarm)
    {
        alarmDao.delete(alarm);

        for (ControllerEventHandler eh : eventHandlers)
        {
            eh.onAlarmDeleted(alarm);
        }
    }

    private double toDouble(String value, String fieldName)
            throws GeoAlarmValidationException
    {
        try
        {
            return Double.parseDouble(value);
        }
        catch (NumberFormatException e)
        {
            throw new GeoAlarmValidationException(String.format(
                    context.getString(R.string.validation_error_format), fieldName));
        }


    }

    private int toInt(String value, String fieldName)
            throws GeoAlarmValidationException
    {
        try
        {
            return Integer.parseInt(value);
        }
        catch (NumberFormatException e)
        {
            throw new GeoAlarmValidationException(String.format(
                    context.getString(R.string.validation_error_format), fieldName));
        }

    }

    public List<AlarmData> getAlarms()
    {
        return alarmDao.getAlarms();
    }

    public void setAlarmState(AlarmData alarm, boolean isChecked)
    {
        alarmDao.setAlarmState(alarm.getId(), isChecked);

        for (ControllerEventHandler eh : eventHandlers)
        {
            eh.onAlarmStateChanged(alarm, isChecked);
        }
    }

    public AlarmData getAlarm(int alarmId)
    {

        return alarmDao.get(alarmId);
    }

    @Override
    public IBinder onBind(Intent intent)
    {
        return binder;
    }

    public class ControllerBinder extends Binder
    {
        GeoAlarmController getService()
        {
            return GeoAlarmController.this;
        }
    }

    public void subscribe(ControllerEventHandler eh)
    {
        eventHandlers.add(eh);
    }

    public void unsubscribe(ControllerEventHandler eh)
    {
        eventHandlers.remove(eh);
    }

    public interface ControllerEventHandler
    {
        void onAlarmAdded(AlarmData alarm);

        void onAlarmDeleted(AlarmData alarm);


        void onAlarmUpdated(AlarmData alarm);

        void onAlarmStateChanged(AlarmData alarm, boolean checked);
    }

}
